package cn.virens.common.pool;

import cn.virens.common.exception.APIException;
import cn.virens.common.utils.Assert;
import org.apache.commons.pool2.DestroyMode;
import org.apache.commons.pool2.KeyedPooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class VirObjectPoolFactoryWarp<K, V> implements KeyedPooledObjectFactory<K, V> {
    private final Map<String, K> aliasMap0 = new ConcurrentHashMap<>();
    private final Map<K, String> aliasMap1 = new ConcurrentHashMap<>();

    private final VirObjectPoolFactory<K, V> factory;

    protected VirObjectPoolFactoryWarp(VirObjectPoolFactory<K, V> factory) {
        this.factory = Assert.isNull(factory, "对象构建工厂不可为空");
    }

    /**
     * 根据别名值获取对应的KEY值
     *
     * @param alias 别名值
     * @return KEY值
     */
    public K getKeyWithAlias(String alias) {
        return aliasMap0.get(alias);
    }

    /**
     * 根据KEY值获取对应的别名值
     *
     * @param key KEY值
     * @return 别名值
     */
    public String getAliasWithKey(K key) {
        return aliasMap1.get(key);
    }

    /**
     * 将对应的KEY值与别名进行绑定
     *
     * @param key   KEY值
     * @param alias 别名值
     */
    public void bindAlias(K key, String alias) throws APIException {
        this.aliasMap0.put(Assert.isEmpty(alias), key);
        this.aliasMap1.put(Assert.isEmpty(key), alias);
    }

    /**
     * 根据KEY值，解除与别名的绑定关系
     *
     * @param key KEY值
     * @throws APIException
     */
    public void unbindAliasWithKey(K key) throws APIException {
        String alias = aliasMap1.remove(Assert.isNull(key));

        if (alias != null && key != null) {
            this.aliasMap0.remove(alias);
        }
    }

    /**
     * 根据别名，解除与KEY值的绑定关系
     *
     * @param alias 别名值
     * @throws APIException
     */
    public void unbindKeyWithAlias(String alias) throws APIException {
        K key = aliasMap0.remove(Assert.isNull(alias));

        if (alias != null && key != null) {
            this.aliasMap1.remove(key);
        }
    }

    @Override
    public PooledObject<V> makeObject(K key) throws Exception {
        return new DefaultPooledObject<>(factory.makeObject(key));
    }

    @Override
    public void destroyObject(K key, PooledObject<V> p) throws Exception {
        this.destroyObject(key, p, DestroyMode.NORMAL);
    }

    @Override
    public void destroyObject(K key, PooledObject<V> p, DestroyMode mode) throws Exception {
        this.unbindAliasWithKey(Assert.isNull(key, "指定对象KEY为空"));
        this.factory.destroyObject(Assert.isNull(key), p, mode);
    }

    @Override
    public boolean validateObject(K key, PooledObject<V> p) {
        return factory.validateObject(Assert.isNull(key), p);
    }

    @Override
    public void activateObject(K key, PooledObject<V> p) throws Exception {
        this.factory.activateObject(Assert.isNull(key), p);
    }

    @Override
    public void passivateObject(K key, PooledObject<V> p) throws Exception {
        this.factory.passivateObject(Assert.isNull(key), p);
    }

}
